package cc.cary.warehouse.untils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.BeanUtils;

import java.io.IOException;
import java.util.*;

/**
 * Beans 辅助类
 *
 * @author Cary
 * @date 2023/1/16
 */
public class Beans {
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    /**
     * 对象是null
     *
     * @param o
     * @return
     */
    public static boolean isNull(Object o) {
        return Objects.isNull(o);
    }

    /**
     * 对象不是null
     *
     * @param o
     * @return
     */
    public static boolean isNotNull(Object o) {
        return Objects.nonNull(o);
    }

    /**
     * 字符串是空字符串
     *
     * @param s
     * @return
     */
    public static boolean strEmpty(String s) {
        return (null == s || "".equals(s.trim()));
    }

    /**
     * 字符串非空
     *
     * @param s
     * @return
     */
    public static boolean strNotEmpty(String s) {
        return !Beans.strEmpty(s);
    }

    /**
     * 对象不是id
     *
     * @param o
     * @return
     */
    public static boolean notId(Object o) {
        return Objects.isNull(o) || "0".equals(String.valueOf(o));
    }

    /**
     * 对象是id
     *
     * @param o
     * @return
     */
    public static boolean id(Object o) {
        return !Beans.notId(o);
    }

    /**
     * 实例化一个对象
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T instance(Class<T> clazz) {
        return BeanUtils.instantiateClass(clazz);
    }

    /**
     * 拷贝一个对象
     *
     * @param src
     * @param targetClazz
     * @param <T>
     * @return
     */
    public static <T> T copy(Object src, Class<T> targetClazz) {
        T target = Beans.instance(targetClazz);
        BeanUtils.copyProperties(src, target);
        return target;
    }

    @FunctionalInterface
    public interface BeansCallBack<S, T> {
        /**
         * 回调
         *
         * @param t
         * @param s
         */
        void callBack(S t, T s);
    }

    /**
     * list copy
     *
     * @param sources
     * @param targetClazz
     * @param <S>
     * @param <T>
     * @return
     */
    public static <S, T> List<T> copyList(List<S> sources, Class<T> targetClazz) {
        return copyList(sources, targetClazz, null);
    }

    /**
     * list copy
     *
     * @param sources
     * @param targetClazz
     * @param callBack
     * @param <S>
     * @param <T>
     * @return
     */
    public static <S, T> List<T> copyList(List<S> sources, Class<T> targetClazz, BeansCallBack<S, T> callBack) {
        List<T> list = new ArrayList<>(sources.size());
        for (S source : sources) {
            T target = copy(source, targetClazz);
            if (isNotNull(callBack)) {
                callBack.callBack(source, target);
            }
            list.add(target);
        }
        return list;
    }

    /**
     * 对象转成json
     *
     * @param o
     * @return
     */
    public static String json(Object o) {
        try {
            return OBJECT_MAPPER.writeValueAsString(o);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return "{}";
    }

    /**
     * 从json转成对象
     *
     * @param json
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T beans(String json, Class<T> clazz) {
        try {
            return OBJECT_MAPPER.readValue(json, clazz);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Beans.instance(clazz);
    }

    /**
     * 从对象转成map
     *
     * @param o
     * @return
     */
    public static Map<String, Object> maps(Object o) {
        try {
            return OBJECT_MAPPER.readValue(Beans.json(o),
                    new TypeReference<Map<String, Object>>() {
                    });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Collections.emptyMap();
    }

    /**
     * 从map转成对象
     *
     * @param o
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T obj(Map<String, Object> o, Class<T> clazz) {
        return Beans.beans(Beans.json(o), clazz);
    }
}
